import paho.mqtt.client as mqtt_client
from paho.mqtt.client import CallbackAPIVersion
import serial
import random
import sys
import os

# 配置参数
MQTT_BROKER = "127.0.0.1"
MQTT_TOPIC = "iot/farm/control"
CLIENT_ID = f"control_subscriber_{random.randint(0, 1000)}"

# 择串口号

SERIAL_PORT = "COM3"  
BAUD_RATE = 9600

# 连接串口
def setup_serial():
    try:
        ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
        print(f"[串口] 已连接至 {SERIAL_PORT}")
        return ser
    except serial.SerialException as e:
        print(f"[错误] 无法打开串口 {SERIAL_PORT}: {e}")
        return None

# 连接回调函数
def on_connect(client, userdata, flags, rc, properties=None):
    if rc == 0:
        print("[MQTT] 成功连接 Broker")
        client.subscribe(MQTT_TOPIC)
    else:
        print(f"[MQTT] 连接失败，返回码: {rc}")

# 消息回调函数 ，对串口对象进行写处理，发送指令到串口
def on_message(client, userdata, msg):
    if msg.topic == MQTT_TOPIC:
        payload = msg.payload.decode()
        print(f"[MQTT] 收到命令: {payload}")

        try:
            device, command = payload.split(":")
            ser = userdata['ser']  # 从 userdata 中获取串口对象
            if ser and ser.is_open:
                ser.write(f"{device},{command}\n".encode())
                print(f"[串口] 发送数据: {device},{command}")
            else:
                print("[错误] 串口未打开")
        except Exception as e:
            print(f"[错误] 解析/发送命令失败: {e}")

def run():
    ser = setup_serial()
    if not ser:
        print("[错误] 串口初始化失败，程序退出")
        return

    client = mqtt_client.Client(
        callback_api_version=CallbackAPIVersion.VERSION2,
        client_id=CLIENT_ID
    )
    client.user_data_set({'ser': ser})  # 将串口对象传入 MQTT 回调中
    client.on_connect = on_connect
    client.on_message = on_message # 

    try:
        client.connect(MQTT_BROKER)
        print(f"[MQTT] 正在监听主题: {MQTT_TOPIC}")
        client.loop_forever()
    except KeyboardInterrupt:
        print("\n[退出] 用户中断程序")
    except Exception as e:
        print(f"[错误] MQTT 连接异常: {e}")
    finally:
        if ser and ser.is_open:
            ser.close()
            print("[串口] 已关闭串口")

if __name__ == '__main__':
    run()